package com.landun.market.web.controller;

import com.landun.market.exception.BusinessException;
import com.landun.market.pojo.enums.ResponseCode;
import com.landun.market.pojo.enums.StateCode;
import com.landun.market.pojo.model.Category;
import com.landun.market.service.ICategoryService;
import com.landun.market.util.NumberUtils;
import com.landun.market.web.domain.ApiOut;
import com.landun.market.web.domain.CategoryVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 品类维护
 *
 * @author jiang.chuan
 * @date 2018-05-05
 */
@Slf4j
@RestController
@RequestMapping("/categories")
public class CategoryController extends AbstractController {
    private final ICategoryService categoryService;

    @Autowired
    public CategoryController(ICategoryService categoryService) {
        this.categoryService = categoryService;
    }

    /**
     * 查询所有品类列表
     *
     * @param keyword   查询的关键字
     * @param pageIndex 当前页码
     * @param pageSize  每页显示品类条数
     * @return 品类列表
     */
    @GetMapping(produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ApiOut<List<CategoryVO>> getAllCategories(
            @RequestParam(name = "q", required = false) String keyword,
            @RequestParam(name = "page", required = false, defaultValue = "1") Integer pageIndex,
            @RequestParam(name = "count", required = false, defaultValue = "10") Integer pageSize) {

        // 按统一格式返回数据
        return new ApiOut.Builder<List<CategoryVO>>(true)
                .data(toTree(categoryService.findAll(), keyword))
                .build();
    }

    /**
     * 查询品类详情
     *
     * @param categoryId 品类ID
     * @return 品类详情
     */
    @GetMapping(path = "/{categoryId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ApiOut<CategoryVO> categoryDetail(@PathVariable("categoryId") Integer categoryId) {

        // 按统一格式返回数据
        return new ApiOut.Builder<CategoryVO>(true)
                .data(toVo(categoryService.load(categoryId)))
                .build();
    }

    /**
     * 检查名字是否重复
     *
     * @param categoryName 品类名
     * @param categoryId   需要排除的品类ID
     * @return true: 品类已经存在，false: 品类不存在
     */
    @GetMapping(path = "/duplicate/{categoryName}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ApiOut<Boolean> isCategoryNameDuplicated(
            @PathVariable("categoryName") String categoryName,
            @RequestParam(name = "id", required = false) Integer categoryId) {

        categoryName = decodeString(categoryName);
        if (StringUtils.isBlank(categoryName)) {
            throw new BusinessException(ResponseCode.PARAMETER_REQUIRED, "品类名");
        }

        return new ApiOut.Builder<Boolean>(true)
                .data(categoryService.isNameDuplicated(categoryName, categoryId))
                .build();
    }


    @ResponseStatus(HttpStatus.CREATED)
    @PostMapping(produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ApiOut<Boolean> createCategory(@RequestBody CategoryVO category) {

        //  校验证参数
        if (null == category) {
            throw new BusinessException(ResponseCode.PARAMETER_REQUIRED, "品类");
        }

        if (StringUtils.isBlank(category.getName())) {
            throw new BusinessException(ResponseCode.PARAMETER_REQUIRED, "品类名");
        }

        // 保存数据
        return categoryService.create(category.toEntity())
                ? new ApiOut.Builder<Boolean>().code(ResponseCode.SUCCESS).data(true).build()
                : new ApiOut.Builder<Boolean>().code(ResponseCode.CREATE_FAILED).message("保存品类失败").data(false).build();
    }

    @PutMapping(path = "/{categoryId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ApiOut<Boolean> updateCategory(@PathVariable("categoryId") Integer categoryId, @RequestBody CategoryVO category) {
        //  校验证参数
        if (NumberUtils.isNotPositive(categoryId)) {
            throw new BusinessException(ResponseCode.PARAMETER_FORMAT_ERROR, "品类ID");
        }

        if (null == category) {
            throw new BusinessException(ResponseCode.PARAMETER_REQUIRED, "品类");
        }

        // 保存数据
        category.setId(categoryId);
        return categoryService.update(category.getId(), category.toEntity())
                ? new ApiOut.Builder<Boolean>().code(ResponseCode.SUCCESS).data(true).build()
                : new ApiOut.Builder<Boolean>().code(ResponseCode.UPDATE_FAILED).message("更新品类失败").data(false).build();
    }

    /**
     * 调整品类排序
     *
     * @param categoryIds，以数组的方式传参：[0] 表示需要排序在前面的品类， [1] 需要排序在后面的品类
     * @return true: 修改成功， false: 修改失败
     */
    @PostMapping(path = "/rearrange", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ApiOut<Boolean> rearrangeCategory(@RequestBody Integer[] categoryIds) {

        // 校验证参数
        if (ArrayUtils.isEmpty(categoryIds) || 2 != categoryIds.length) {
            throw new BusinessException(ResponseCode.PARAMETER_REQUIRED, "重排序的品类IDs");
        }

        Integer topId = categoryIds[0];
        Integer bottomId = categoryIds[1];
        if (NumberUtils.isNotPositive(topId) || NumberUtils.isNotPositive(bottomId)) {
            throw new BusinessException(ResponseCode.PARAMETER_REQUIRED, "重排序的品类IDs");
        }

        // 调整顺序
        return categoryService.rearrange(topId, bottomId)
                ? new ApiOut.Builder<Boolean>().code(ResponseCode.SUCCESS).data(true).build()
                : new ApiOut.Builder<Boolean>().code(ResponseCode.REARRANGE_FAILED).message("对品类重排序失败").data(false).build();
    }

    @PutMapping(path = "/disable/{categoryId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ApiOut<Boolean> disableCategory(@PathVariable("categoryId") Integer categoryId) {
        // 校验证参数
        if (NumberUtils.isNotPositive(categoryId)) {
            throw new BusinessException(ResponseCode.PARAMETER_REQUIRED, "品类ID");
        }

        // 禁用品类
        return categoryService.changeStatus(StateCode.INACTIVE, categoryId)
                ? new ApiOut.Builder<Boolean>().code(ResponseCode.SUCCESS).data(true).build()
                : new ApiOut.Builder<Boolean>().code(ResponseCode.DISABLE_FAILED)
                .message("禁用品类" + categoryId + "失败").data(false).build();
    }


    @PutMapping(path = "/enable/{categoryId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ApiOut<Boolean> enableCategory(@PathVariable("categoryId") Integer categoryId) {
        // 校验证参数
        if (NumberUtils.isNotPositive(categoryId)) {
            return new ApiOut.Builder<Boolean>().code(ResponseCode.PARAMETER_REQUIRED).build();
        }

        // 删除数据
        return categoryService.changeStatus(StateCode.ACTIVE, categoryId)
                ? new ApiOut.Builder<Boolean>().code(ResponseCode.SUCCESS).data(true).build()
                : new ApiOut.Builder<Boolean>().code(ResponseCode.ENABLE_FAILED)
                .message("启用品类" + categoryId + "失败").data(false).build();
    }

    /**
     * 将品类转换成树的形式
     *
     * @param categories 已经存在的品类列表
     * @param keyword    需要匹配的关键字
     * @return 品类树
     */
    private List<CategoryVO> toTree(List<Category> categories, String keyword) {
        if (CollectionUtils.isEmpty(categories)) {
            return new ArrayList<>(0);
        }

        // 按数据库中的排序
        Map<Integer, CategoryVO> categoryMap = categories.stream()
                .map(this::toVo)
                .collect(Collectors.toMap(CategoryVO::getId, cat -> cat));

        // 组织成树的形式
        List<CategoryVO> firstLevelCategories = new ArrayList<>();
        categories.forEach(cat -> {
            if (null != cat.getParentId()) {
                if (cat.getParentId() > 0 && categoryMap.containsKey(cat.getParentId())) {
                    CategoryVO parent = categoryMap.get(cat.getParentId());
                    parent.addChild(categoryMap.get(cat.getId()));
                } else if (cat.getParentId() == 0
                        || categoryService.TOP_LEVEL == Optional.ofNullable(cat.getLevel()).orElse(1)) {
                    firstLevelCategories.add(categoryMap.get(cat.getId()));
                }
            }
        });

        // 对一级关键字进行过滤
        return StringUtils.isBlank(keyword)
                ? firstLevelCategories
                : firstLevelCategories.stream()
                .filter(category -> StringUtils.containsIgnoreCase(category.getName(), keyword.trim()))
                .collect(Collectors.toList());
    }

    private CategoryVO toVo(Category CategoryVO) {
        return new CategoryVO(CategoryVO);
    }
}
